/*
 * Copyright 2011-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.sabayframework.cluster.impl;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;

import org.jgroups.Global;
import org.jgroups.util.Streamable;
import org.sabayframework.cluster.ComputerId;
import org.sabayframework.cluster.NodeId;

/**
 * Implementation of computer's NodeId.
 * @author Alex Antonau
 */
public final class ComputerIdImpl implements NodeId, Streamable, ComputerId {

	private static final long serialVersionUID = 1L;
	private InetAddress address;
	private int port;
	
    ComputerIdImpl() {
		super();
	}

	public ComputerIdImpl(InetAddress address, int port) {
		super();
		this.address = address;
		this.port = port;
	}

	/* (non-Javadoc)
	 * @see org.sabayframework.cluster.impl.IComputerId#getAddress()
	 */
	@Override
	public InetAddress getAddress() {
		return address;
	}

	/* (non-Javadoc)
	 * @see org.sabayframework.cluster.impl.IComputerId#getPort()
	 */
	@Override
	public int getPort() {
		return port;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result + port;
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ComputerIdImpl other = (ComputerIdImpl) obj;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (port != other.port)
			return false;
		return true;
	}

	public String toString() {
        return new StringBuilder().append(address).append(":").append(port).toString();
	}

	public void readFrom(DataInput in) throws IOException {
        int len=in.readByte();
        if(len > 0 && (len != Global.IPV4_SIZE && len != Global.IPV6_SIZE))
            throw new IOException("length has to be " + Global.IPV4_SIZE + " or " + Global.IPV6_SIZE + " bytes (was " +
                    len + " bytes)");
        byte[] a = new byte[len]; // 4 bytes (IPv4) or 16 bytes (IPv6)
        in.readFully(a);
        if(len == Global.IPV6_SIZE) {
            int scope_id=in.readInt();
            this.address=Inet6Address.getByAddress(null, a, scope_id);
        }
        else {
            this.address=InetAddress.getByAddress(a);
        }
        port=in.readUnsignedShort();
	}


	public void writeTo(DataOutput out) throws IOException {
        if(address != null) {
            byte[] bytes=address.getAddress();  // 4 bytes (IPv4) or 16 bytes (IPv6)
            out.writeByte(bytes.length); // 1 byte
            out.write(bytes, 0, bytes.length);
            if(address instanceof Inet6Address)
                out.writeInt(((Inet6Address)address).getScopeId());
        }
        else {
            out.writeByte(0);
        }
        out.writeShort(port);
	}

}
